#
#    Copyright 2006 Andrew Wilkinson <aw@cs.york.ac.uk>.
#
#    This file is part of PyScobble (http://lastfm.indiegigs.co.uk/pyscrobble)
#
#    PyScobble is free software; you can redistribute it and/or modify
#    it under the terms of the GNU Lesser General Public License as published by
#    the Free Software Foundation; either version 2.1 of the License, or
#    (at your option) any later version.
#
#    PyScobble is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with PyScobble; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

import sys
import threading
from PyQt4 import QtCore, QtGui
import traceback

import scrobble

import resource
import mainwindow

exception = None
window = None
thread = None

def runGUI(pfindneighbours):
    global findneighbours, window
    findneighbours = pfindneighbours

    app = QtGui.QApplication(sys.argv)
    window = QtGui.QDialog()

    ui = MainWindow()
    ui.setupUi(window)

    window.show()

    sys.exit(app.exec_())

class MainWindow(mainwindow.Ui_MainWindow):
    def __init__(self):
        mainwindow.Ui_MainWindow.__init__(self)

        self.notifylist = []

    def setupUi(self, MainWindow):
        mainwindow.Ui_MainWindow.setupUi(self, MainWindow)

        self.enableWorkingIcons(False)

        self.cacheUsage.setMinimum(0)
        self.cacheUsage.setMaximum(1000)

        self.model = FoundNeighboursModel()
        self.revNeighbours.setModel(self.model)

        header = QtGui.QHeaderView(QtCore.Qt.Horizontal, self.revNeighbours)
        header.setResizeMode(QtGui.QHeaderView.Stretch)
        self.revNeighbours.setHorizontalHeader(header)

        MainWindow.connect(self.FindNeighbours, QtCore.SIGNAL("clicked()"), self.findNeighbours)

    def findNeighbours(self):
        global thread, exception

        if self.FindNeighbours.text() == "Cancel":
            thread.end = True
            self.enableWorkingIcons(False)
            self.timer.stop()
            return

        try:
            f = scrobble.User(str(self.user.text())).neighbours
        except ValueError:
            QtGui.QMessageBox.critical(None, "Last.fm Reverse Neighbours", "User %s does not exist." % (self.user.text(),))
            return
        else:
            if len(f) == 0:
                QtGui.QMessageBox.critical(None, "Last.fm Reverse Neighbours", "User %s has no neighbours :-(" % (self.user.text(),))
                return

        self.model.neighbours = []
        self.revNeighbours.setModel(self.model)
        exception = None

        self.enableWorkingIcons(True)
        thread = FindNeighbours((scrobble.User(str(self.user.text())), self.searchDepth.value(), self.notify, self.model))

        thread.start()

        self.timer = QtCore.QTimer()
        window.connect(self.timer, QtCore.SIGNAL("timeout()"), self.notifyTimer);
        self.timer.start(1000);

    def enableWorkingIcons(self, on):
        self.progressBar.setEnabled(on)
        self.revNeighbours.setEnabled(on)
        self.cacheUsage.setEnabled(on)
        self.status.setEnabled(on)
        self.user.setEnabled(not on)
        self.searchDepth.setEnabled(not on)
        if on:
            self.FindNeighbours.setText("Cancel")
        else:
            self.FindNeighbours.setText("Find Neighbours")

    def notify(self, text, value):
        self.notifylist.append((text, value))

    def notifyTimer(self):
        while len(self.notifylist) > 0:
            (text, value), self.notifylist = self.notifylist[0], self.notifylist[1:]

            if text == "maxprogress":
                self.progressBar.setMaximum(value)
            elif text == "progress":
                self.progressBar.setValue(value)
            elif text == "match":
                self.revNeighbours.setModel(self.model)
            elif text == "done":
                self.timer.stop()
                if thread is not None:
                    thread.end = True
                if exception is not None:
                    QtGui.QMessageBox.critical(None, "Last.fm Reverse Neighbours", "An error occurred. Please email the traceback below, plus details of the user you were find neighbours for to andrew@indiegis.co.uk<br><br>%s" % ("<br>".join(exception),))
                else:
                    QtGui.QMessageBox.information(None, "Last.fm Reverse Neighbours", "Found %i reverse neighbours." % (len(self.model.neighbours), ))
                self.enableWorkingIcons(False)
                self.revNeighbours.setEnabled(True)
            else:
                print text, value
        self.cacheUsage.setValue(int(scrobble.getCacheUsage()*10))
        self.status.setText(scrobble.getStatus())

class FindNeighbours(QtCore.QThread):
    def __init__(self, args):
        QtCore.QThread.__init__(self)
        self.args = args
        self.end = False

    def run(self):
        global exception

        f = findneighbours(self.args[0], self.args[1], self.args[2])

        while not self.end:
            try:
                n = f.next()
            except:
                exctype, excvalue, tb = sys.exc_info()
                exception = traceback.format_exception(exctype, excvalue, tb)
                exception = [e.replace("<", "&lt;").replace(">", "&gt;") for e in exception]
                break
            if not n:
                break
            self.args[3].neighbours = [n] + self.args[3].neighbours
            self.args[2]("match", None)
        if not self.end:
            self.args[2]("done", None)

class FoundNeighboursModel(QtCore.QAbstractTableModel):
    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)

        self.neighbours = []

    def rowCount(self, parent):
        return len(self.neighbours)

    def columnCount(self, parent):
        return 2

    def data(self, index, role):
        if not index.isValid():
            return QtCore.QVariant()

        if index.row() >= len(self.neighbours) or index.column() >= 2:
            return QtCore.QVariant()

        if role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(str(self.neighbours[index.row()][index.column()]))
        else:
            return QtCore.QVariant()

    def headerData(self, section, orientation, role):
        if role != QtCore.Qt.DisplayRole:
            return QtCore.QVariant()

        if orientation == QtCore.Qt.Horizontal:
            if section == 0:
                return QtCore.QVariant("Neighbour")
            else:
                return QtCore.QVariant("Position")
        else:
            return QtCore.QVariant("")
